<template>
  <div
    class="daterang-box not-select"
    ref="dateBox"
    :style="{
      display: dateBoxStyle
    }"
  >
    <div class="d-flex">
      <div style="width: 50%; padding-right: 6px">
        <!-- 值表示 -->
        <div>
          <input type="text" class="input-box" v-model="tmpValue[0]" readonly />
        </div>
        <!-- 日期操作 -->
        <div class="select-box">
          <img src="../assets/left.png" class="next-btn f-left" @click="leftClick" />
          <span>
            <select style="width: 80px; margin-right: 5px" v-model="leftMonthValue">
              <option
                v-for="item in months"
                :key="item.value"
                :value="item.value"
                v-show="clacMonthStatus('L', item.value)"
              >
                {{ item.label }}
              </option>
            </select>
            <select style="width: 80px; margin-right: 5px" v-model="startYearValue">
              <option v-for="item in leftYears" :key="item" :value="item">
                {{ item }}
              </option>
            </select>
          </span>
        </div>
        <!-- 日期表示 -->
        <div class="d-flex">
          <div style="width: 32px; height: 100%" @click="itemLeftClick($event)">
            <div class="week-title">周</div>
            <div :class="item.class" v-for="item in leftWeekCounts" :key="item.id" :data-value="item.id">
              {{ item.label }}
            </div>
          </div>
          <ul class="item-box">
            <li class="week-title" v-for="label in weekLabel" :key="label">{{ label }}</li>
            <li :class="item.class" :data-value="item.value" v-for="item in leftDayCount" :key="item.value">
              {{ item.label }}
            </li>
          </ul>
        </div>
      </div>
      <div style="width: 50%; padding-right: 6px">
        <!-- 值表示 -->
        <div>
          <input type="text" class="input-box" v-model="tmpValue[1]" readonly />
        </div>
        <!-- 日期操作 -->
        <div class="select-box">
          <span>
            <select style="width: 80px; margin-right: 5px" v-model="rightMonthValue">
              <option
                v-for="item in months"
                :key="item.value"
                :value="item.value"
                v-show="clacMonthStatus('R', item.value)"
              >
                {{ item.label }}
              </option>
            </select>
            <select style="width: 80px; margin-right: 5px" v-model="endYearValue">
              <option v-for="item in rightYears" :key="item" :value="item">
                {{ item }}
              </option>
            </select>
          </span>
          <img src="../assets/right.png" class="next-btn f-right" @click="nextClick" />
        </div>
        <!-- 日期表示 -->
        <div class="d-flex">
          <div style="width: 32px; height: 100%" @click="itemRightClick($event)">
            <div class="week-title">周</div>
            <div :class="item.class" v-for="item in rightWeekCounts" :key="item.id" :data-value="item.id">
              {{ item.label }}
            </div>
          </div>
          <ul class="item-box">
            <li class="week-title" v-for="label in weekLabel" :key="label">{{ label }}</li>
            <li :class="item.class" :data-value="item.value" v-for="item in rightDayCount" :key="item.value">
              {{ item.label }}
            </li>
          </ul>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { computed, reactive, ref, toRefs } from '@vue/reactivity';
import { nextTick, watch } from '@vue/runtime-core';
export default {
  name: 'WeekRange'
};
</script>
<script setup>
//声明月份
const months = reactive([
  { label: '1月', value: 1 },
  { label: '2月', value: 2 },
  { label: '3月', value: 3 },
  { label: '4月', value: 4 },
  { label: '5月', value: 5 },
  { label: '6月', value: 6 },
  { label: '7月', value: 7 },
  { label: '8月', value: 8 },
  { label: '9月', value: 9 },
  { label: '10月', value: 10 },
  { label: '11月', value: 11 },
  { label: '12月', value: 12 }
]);
const weekLabel = ref(['一', '二', '三', '四', '五', '六', '七']);
//eslint-disable-next-line
const props = defineProps({
  visible: Boolean,
  min: String,
  max: String,
  value: Array,
  weekInfo: Object
});
//eslint-disable-next-line
const emits = defineEmits(['update:visible', 'update:value']);
const moment = window.moment;
const { visible, max, min, value, weekInfo } = toRefs(props);

/**
 * 日期转换周
 * @param String 日期字符串 YYYYMMDD
 * @return String 周字符串 YYYYWW
 */
const calcDateWeekInfo = function (info) {
  let year = info.slice(0, 4);
  let nextYear = +year + 1;
  let nowYearStartDate = weekInfo.value[year + ''];
  let nextYearStartDate = weekInfo.value[nextYear + ''];
  if (+info < +nowYearStartDate) {
    year = +year - 1;
  } else if (+info >= +nextYearStartDate) {
    year = +year + 1;
  } else {
    //no thing
  }
  let yearStartDate = moment(weekInfo.value[year + ''], 'YYYYMMDD');
  let infoMoment = moment(info, 'YYYYMMDD');
  let weekCount = String(infoMoment.diff(yearStartDate, 'days') / 7 + 1)
    .split('.')
    .shift()
    .padStart(2, '0');
  return `${year}${weekCount}`;
};

/**
 * 周转换日期
 * @param String 日期字符串 YYYYMMDD
 * @return String 周字符串 YYYYWW
 */
const clacWeek2Date = function (info) {
  let yearStartDate = moment(weekInfo.value[info.slice(0, 4)], 'YYYYMMDD');
  let daysCount = +info.slice(4, 6) * 7;
  yearStartDate.add(daysCount, 'days');
  return yearStartDate.format('YYYYMMDD');
};

//限制的最大周和最小周
const maxWeek = calcDateWeekInfo(max.value);
const minWeek = calcDateWeekInfo(min.value);

//临时操作值
const tmpValue = ref(value.value);
//打开时刷新画面数据
watch(visible, () => {
  if (!visible.value) {
    nextTick(() => {
      tmpValue.value = value.value;
      const startTime = moment(clacWeek2Date(value.value[0]), 'YYYYMMDD');
      const endTime = moment(clacWeek2Date(value.value[1]), 'YYYYMMDD');
      const maxDate = moment(max.value, 'YYYYMMDD').format('YYYYMM');
      if (startTime.format('YYYYMM') === endTime.format('YYYYMM')) {
        if (endTime.format('YYYYMM') === maxDate) {
          startTime.subtract(1, 'months');
        } else {
          endTime.add(1, 'months');
        }
      }
      startYear.value = startTime.get('year');
      endYear.value = endTime.get('year');
      leftMonthValue.value = startTime.get('month') + 1;
      rightMonthValue.value = endTime.get('month') + 1;
    });
  } else {
    if (tmpValue.value.toString() !== value.value.toString()) {
      tmpValue.value = value.value;
    }
  }
});
//左侧月值
const leftMonthValue = ref(+clacWeek2Date(value.value[0]).slice(4, 6));
//右侧月值
const rightMonthValue = ref(+clacWeek2Date(value.value[1]).slice(4, 6));
//左侧天数
const leftDayCount = computed(() => {
  return calcMonthInfo(startYear.value, leftMonthValue.value);
});
//左侧周编码
const leftWeekCounts = computed(() => {
  return calcWeekCount(leftDayCount.value);
});
//右侧天数
const rightDayCount = computed(() => {
  return calcMonthInfo(endYear.value, rightMonthValue.value);
});
//右侧周编码
const rightWeekCounts = computed(() => {
  return calcWeekCount(rightDayCount.value);
});
//计算年范围
const years = computed(() => {
  let maxYears = moment(max.value, 'YYYYMMDD').get('year');
  let minYears = moment(min.value, 'YYYYMMDD').get('year');
  let results = [];
  while (minYears <= maxYears) {
    results.push(minYears++);
  }
  return results;
});
//左侧年列表
const leftYears = computed(() => {
  let left = Object.assign([], years.value);
  return left;
});
//右侧年列表
const rightYears = computed(() => {
  let right = Object.assign([], years.value);
  return right;
});
//开始年
const startYear = ref(clacWeek2Date(value.value[0]).slice(0, 4));
const startYearValue = computed({
  get() {
    return startYear.value;
  },
  set(value) {
    startYear.value = value;
  }
});
//结束年
const endYear = ref(clacWeek2Date(value.value[1]).slice(0, 4));
const endYearValue = computed({
  get() {
    return endYear.value;
  },
  set(value) {
    endYear.value = value;
  }
});

watch([startYear, leftMonthValue], () => {
  let startDate = `${startYear.value}${leftMonthValue.value.toString().padStart(2, '0')}`;
  let endDate = `${endYear.value}${rightMonthValue.value.toString().padStart(2, '0')}`;
  if (+startDate > +endDate) {
    const startDateMoment = moment(startDate, 'YYYYMM').add(1, 'months');
    endYearValue.value = startDateMoment.get('year');
    rightMonthValue.value = startDateMoment.get('month') + 1;
  }
  //防止选择到范围外的日期
  let minDate = moment(min.value, 'YYYYMMDD');
  if (+startDate < +minDate.format('YYYYMM')) {
    startYearValue.value = minDate.get('year');
    leftMonthValue.value = minDate.get('month') + 1;
  }
});

/**
 * 监听结束年月，防止结束年月大于开视年月
 */
watch([endYear, rightMonthValue], () => {
  let endDate = `${endYear.value}${rightMonthValue.value.toString().padStart(2, '0')}`;
  let startDate = `${startYear.value}${leftMonthValue.value.toString().padStart(2, '0')}`;
  if (+endDate < +startDate) {
    const endDateMoment = moment(endDate, 'YYYYMM').subtract(1, 'months');
    startYearValue.value = endDateMoment.get('year');
    leftMonthValue.value = endDateMoment.get('month') + 1;
  }
  //防止选择到范围外的日期
  let maxDate = moment(max.value, 'YYYYMMDD');
  if (+endDate > +maxDate.format('YYYYMM')) {
    endYearValue.value = maxDate.get('year');
    rightMonthValue.value = maxDate.get('month') + 1;
  }
  let minMoment = moment(min.value, 'YYYYMMDD').add(1, 'month');
  if (+endDate < +minMoment.format('YYYYMM')) {
    endYearValue.value = minMoment.get('year');
    rightMonthValue.value = minMoment.get('month') + 1;
  }
});

/**
 * 监听结束年的改变
 * 根据结束年的数据设置月份可用情况
 */
// watch(endYear, () => {
//   let maxYears = moment(max.value, 'YYYYMMDD').get('year');
//   if (endYear.value === maxYears) {
//     minMonth.value = moment(max.value, 'YYYYMMDD').get('month');
//   } else {
//     minMonth.value = 13;
//   }
// });

//左右按钮点击事件
const leftClick = () => {
  if (leftMonthValue.value === 1 && +startYear.value > years.value[0]) {
    startYear.value = startYear.value - 1;
    leftMonthValue.value = 12;
  } else {
    leftMonthValue.value = leftMonthValue.value - 1;
  }
};
const nextClick = () => {
  if (rightMonthValue.value === 12 && +endYear.value < years.value[years.value.length - 2]) {
    endYear.value = endYear.value + 1;
    rightMonthValue.value = 1;
  } else {
    rightMonthValue.value = rightMonthValue.value + 1;
  }
};

/**
 * 显示悬浮窗
 */
const dateBoxStyle = computed(() => {
  if (visible.value) {
    return 'block';
  } else {
    return 'none';
  }
});

/**
 * 时间点击事件
 */
const itemLeftClick = (event) => {
  if (event.target.className.includes('not-item') || !event.target.className.includes('item')) {
    return;
  }
  let value = event.target.getAttribute('data-value') ?? '';
  if (tmpValue.value.length === 2) {
    tmpValue.value = [];
  }
  tmpValue.value.push(value);
  tmpValue.value.sort((item1, item2) => {
    return +item1 - +item2;
  });
  if (tmpValue.value.length === 2) {
    emits('update:value', tmpValue.value);
    emits('update:visible', false);
  }
};
const itemRightClick = (event) => {
  if (event.target.className.includes('not-item') || !event.target.className.includes('item')) {
    return;
  }
  let value = event.target.getAttribute('data-value') ?? '';
  if (tmpValue.value.length === 2) {
    tmpValue.value = [];
  }
  tmpValue.value.push(value);
  tmpValue.value.sort((item1, item2) => {
    return +item1 - +item2;
  });
  if (tmpValue.value.length === 2) {
    emits('update:value', tmpValue.value);
    emits('update:visible', false);
  }
};

/**
 * 月份详细天信息计算函数
 */
const calcMonthInfo = (year, month) => {
  let result = [];
  //获取当月开始是周几
  let yearStartDate = moment(weekInfo.value[year], 'YYYYMMDD');
  let localDateStart = moment(`${year}${month.toString().padStart(2, '0')}01`, 'YYYYMMDD');
  let localDateEnd = moment(`${year}${month.toString().padStart(2, '0')}01`, 'YYYYMMDD').endOf('month');
  let subCount = localDateStart.diff(yearStartDate, 'days') % 7; //当月开始日是周几
  if (subCount !== 0) {
    localDateStart.subtract(subCount, 'days');
  }
  //获取当月结束日是周几
  subCount = localDateEnd.diff(yearStartDate, 'days') % 7;
  localDateEnd.add(7 - subCount, 'days');
  while (localDateEnd.diff(localDateStart, 'days') > 0) {
    let param = {
      class: 'not-item',
      label: localDateStart.get('date'),
      value: localDateStart.format('YYYYMMDD')
    };
    result.push(param);
    localDateStart.add(1, 'days');
  }
  return result;
};

/**
 * 计算周的数据
 */
const calcWeekCount = function (dateInfos) {
  const weekCounts = {};
  for (let item of dateInfos) {
    let yearWeek = calcDateWeekInfo(item.value);
    if (!(yearWeek in weekCounts)) {
      weekCounts[yearWeek] = {
        id: yearWeek,
        label: yearWeek.slice(4, 6),
        class: calcItemClass(yearWeek)
      };
    }
  }
  return Object.values(weekCounts);
};

/**
 * 计算当前日期的class
 */
const calcItemClass = (info) => {
  let classes = [];
  if (info === tmpValue.value[0] || info === tmpValue.value[1]) {
    classes.push('item item-active');
  } else if (+info > +tmpValue.value[0] && +info < +tmpValue.value[1]) {
    classes.push('item item-range');
  } else if (+info < +minWeek || +info > maxWeek) {
    classes.push('not-item');
  } else {
    classes.push('item');
  }
  return classes;
};
/**
 * 计算当前年应该显示哪些月份信息
 * @param {String} type 位置信息： L/R
 * @param {String} value 月份信息
 */
const clacMonthStatus = (type, value) => {
  let minMoment = moment(min.value, 'YYYYMMDD');
  let maxMoment = moment(max.value, 'YYYYMMDD');
  let year = type === 'L' ? startYearValue.value : endYearValue.value;
  if (year !== +minMoment.format('YYYY') && year !== +maxMoment.format('YYYY')) {
    return true;
  }
  if (year === +minMoment.format('YYYY')) {
    let minMonth = +minMoment.format('MM');
    type === 'R' ? minMonth++ : null;
    return +value >= minMonth;
  }
  if (year === +maxMoment.format('YYYY')) {
    let maxMonth = +maxMoment.format('MM');
    type === 'L' ? maxMonth-- : null;
    return +value <= +maxMonth;
  }
};
</script>
<style lang="scss" scoped>
.daterang-box {
  padding: 12px;
  position: absolute;
  margin-top: 4px;
  display: none;
  box-shadow: 0px 0px 5px 5px #eeeeee;
  width: 560px;
  background: #ffffff;
  border-radius: 8px;
  text-align: left;
}
.input-box {
  height: 30px;
  width: 100%;
  background: url(../assets/calendar.png) no-repeat;
  background-size: 20px 20px;
  background-position-y: 3px;
  padding-left: 25px;
  padding-right: 25px;
  border-radius: 4px;
}
.select-box {
  padding: 6px 0px;
}
.next-btn {
  height: 20px;
  width: 20px;
  cursor: pointer;
}
.next-btn:hover {
  background: #eeeeee;
}
.item-box {
  list-style: none;
  padding: 0px;
  margin: 0px;
}
.week-title {
  display: inline-block;
  width: 32px;
  height: 32px;
  line-height: 32px;
  border-radius: 4px;
  text-align: center;
}
.item {
  display: inline-block;
  width: 32px;
  height: 32px;
  line-height: 32px;
  cursor: pointer;
  border-radius: 4px;
  text-align: center;
}
.not-item {
  display: inline-block;
  width: 32px;
  height: 32px;
  line-height: 32px;
  color: #898989;
  border-radius: 4px;
  text-align: center;
}
.item:hover {
  background: #eeeeee;
}
.item-active {
  background: #357ebd !important;
}
.item-range {
  background: #dbdbdb;
  border-radius: 0px !important;
}
</style>